﻿using System;
using System.Data;
using System.Globalization;
using System.IO;
using System.Text;

namespace WpfCsvDemo
{
    /// <summary>
    /// CSV文件读写工具类
    /// 提供读取和写入CSV文件的功能
    /// 支持处理包含特殊字符（如逗号、引号、换行符）的字段
    /// </summary>
    public static class CsvHelper
    {
        /// <summary>
        /// 读取CSV文件并返回DataTable
        /// </summary>
        /// <param name="filePath">CSV文件路径</param>
        /// <returns>包含CSV数据的DataTable</returns>
        public static DataTable ReadCsv(string filePath)
        {
            DataTable dataTable = new DataTable();
            dataTable.Locale = CultureInfo.InvariantCulture;

            try
            {
                using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
                {
                    // 读取首行作为列标题
                    string headerLine = reader.ReadLine();
                    if (string.IsNullOrEmpty(headerLine))
                    {
                        throw new Exception("CSV文件为空或格式不正确");
                    }

                    // 解析列标题
                    string[] headers = ParseCsvLine(headerLine);
                    foreach (string header in headers)
                    {
                        // 创建列，处理重复列名
                        string columnName = header.Trim();
                        if (dataTable.Columns.Contains(columnName))
                        {
                            int count = 1;
                            while (dataTable.Columns.Contains($"{columnName}_{count}"))
                            {
                                count++;
                            }
                            columnName = $"{columnName}_{count}";
                        }
                        dataTable.Columns.Add(columnName);
                    }

                    // 读取数据行
                    while (!reader.EndOfStream)
                    {
                        string dataLine = reader.ReadLine();
                        if (string.IsNullOrWhiteSpace(dataLine)) continue;

                        string[] rowValues = ParseCsvLine(dataLine);
                        DataRow row = dataTable.NewRow();

                        // 处理列数不一致的情况
                        for (int i = 0; i < Math.Min(rowValues.Length, dataTable.Columns.Count); i++)
                        {
                            row[i] = rowValues[i].Trim();
                        }

                        dataTable.Rows.Add(row);
                    }
                }

                return dataTable;
            }
            catch (Exception ex)
            {
                throw new Exception($"读取CSV文件时出错: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 将DataTable数据保存到CSV文件
        /// </summary>
        /// <param name="data">要保存的数据</param>
        /// <param name="filePath">目标文件路径</param>
        public static void SaveCsv(DataTable data, string filePath)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data), "数据表不能为空");
            }

            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
                {
                    // 写入列标题
                    for (int i = 0; i < data.Columns.Count; i++)
                    {
                        writer.Write(EscapeCsvField(data.Columns[i].ColumnName));
                        if (i < data.Columns.Count - 1)
                        {
                            writer.Write(",");
                        }
                    }
                    writer.WriteLine();

                    // 写入数据行
                    foreach (DataRow row in data.Rows)
                    {
                        for (int i = 0; i < data.Columns.Count; i++)
                        {
                            writer.Write(EscapeCsvField(row[i]?.ToString() ?? ""));
                            if (i < data.Columns.Count - 1)
                            {
                                writer.Write(",");
                            }
                        }
                        writer.WriteLine();
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"保存CSV文件时出错: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 解析CSV行，处理引号包裹的字段和转义字符
        /// </summary>
        private static string[] ParseCsvLine(string line)
        {
            List<string> fields = new List<string>();
            StringBuilder currentField = new StringBuilder();
            bool inQuotes = false;
            bool escapeNext = false;

            for (int i = 0; i < line.Length; i++)
            {
                char c = line[i];

                if (escapeNext)
                {
                    // 处理转义字符
                    currentField.Append(c);
                    escapeNext = false;
                }
                else if (c == '"')
                {
                    if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
                    {
                        // 双引号表示转义引号
                        currentField.Append('"');
                        i++; // 跳过下一个引号
                    }
                    else
                    {
                        // 切换引号状态
                        inQuotes = !inQuotes;
                    }
                }
                else if (c == '\\')
                {
                    // 反斜杠转义下一个字符
                    escapeNext = true;
                }
                else if (c == ',' && !inQuotes)
                {
                    // 逗号分隔符（不在引号内）
                    fields.Add(currentField.ToString());
                    currentField.Clear();
                }
                else
                {
                    currentField.Append(c);
                }
            }

            // 添加最后一个字段
            fields.Add(currentField.ToString());

            return fields.ToArray();
        }

        /// <summary>
        /// 转义CSV字段中的特殊字符
        /// </summary>
        private static string EscapeCsvField(string field)
        {
            if (string.IsNullOrEmpty(field))
            {
                return "";
            }

            // 检查是否需要引号包裹
            bool needsQuotes = field.Contains(",") ||
                                field.Contains("\"") ||
                                field.Contains("\n") ||
                                field.Contains("\r");

            // 替换字段内的引号为双引号
            string escapedField = field.Replace("\"", "\"\"");

            return needsQuotes ? $"\"{escapedField}\"" : escapedField;
        }
    }
}